using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;

namespace UWBGL_XNA_Lib13
{
    public class UWB_XNADrawHelper : UWB_DrawHelper
    {

        public UWB_XNADrawHelper()
        {
        }

        public override bool drawPoint(Vector3 position)
        {
            GraphicsDevice device = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            Debug.Assert(device != null, "device not valid on DrawHelper drawCircle call");
            DeviceVertexFormat[] v = new DeviceVertexFormat[1];
            v[0].Position = position;
            v[0].Color = mColor1;
            v[0].U = 0.0f;
            v[0].V = 0.0f;

            float pointSize = device.RenderState.PointSize;
            device.RenderState.PointSize = mPointSize;
            device.RenderState.PointSpriteEnable = true;
            device.DrawUserPrimitives(PrimitiveType.PointList, v, 0, 1);

            return true;
        }

        public override bool drawLine(Vector3 start, Vector3 end)
        {
            GraphicsDevice device = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            Debug.Assert(device != null, "device not valid on DrawHelper drawCircle call");
            DeviceVertexFormat[] v = new DeviceVertexFormat[2];

            Color flatColor = mColor1;

            v[0].Position = start;
            v[0].Color = flatColor;
            v[0].U = 0.0f;
            v[0].V = 0.0f;

            v[1].Position = end;
            v[1].U = 1.0f;
            v[1].V = 1.0f;

            if (mShadeMode == eShadeMode.smFlat)
                v[1].Color = flatColor;
            else
                v[1].Color = mColor2;

            device.DrawUserPrimitives(PrimitiveType.LineList, v, 0, 1);
            if (mbTexturingEnabled)
                UWB_XNAGraphicsSystem.m_TheAPI.DeactivateTexture();

            return true;
        }

        public override bool drawCircle(Vector3 center, float radius)
        {
            GraphicsDevice device = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            Debug.Assert(device != null, "device not valid on DrawHelper drawCircle call");
            
            if (radius > 0)
            {
                int kNumPts = 40;
                if (mLod == eLevelofDetail.lodLow)
                    kNumPts = 10;
                else if (mLod == eLevelofDetail.lodMed)
                    kNumPts = 20;
                DeviceVertexFormat[] v = new DeviceVertexFormat[kNumPts];

                float delta = (float)(UWB_Math.UWB_ToRadians((float)360 / (float)(kNumPts - 2)));

                Color flatColor = mColor1;

                v[0].Position = new Vector3(center.X, center.Y, 0f);
                v[0].Color = flatColor;
                v[0].U = 0.5f;
                v[0].V = 0.5f;

                for (int i = 0; i < (kNumPts - 2); i++)
                {
                    float X = center.X + (radius * (float)Math.Cos(i * delta));
                    float Y = center.Y + (radius * (float)Math.Sin(i * delta));
                    v[i + 1].Position = new Vector3(X, Y, 0f);
                    v[i + 1].Color = flatColor;
                    v[i + 1].U = 0.5f + (0.5f * (float)Math.Cos(i * delta));
                    v[i + 1].V = 0.5f - (0.5f * (float)Math.Sin(i * delta));
                }
                v[kNumPts - 1] = v[1];

                if (mShadeMode == eShadeMode.smGouraud)
                    v[0].Color = mColor2;

               device.DrawUserPrimitives(PrimitiveType.TriangleFan, v, 0, (kNumPts - 2));
               if (mbTexturingEnabled)
                   UWB_XNAGraphicsSystem.m_TheAPI.DeactivateTexture();

            }
            return true;
        }

        public override bool drawStar(Vector3 center, float radius)
        {
            GraphicsDevice device = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            Debug.Assert(device != null, "device not valid on DrawHelper drawCircle call");

            if (radius > 0)
            {
                int kNumPts = 40;
                if (mLod == eLevelofDetail.lodLow)
                    kNumPts = 10;
                else if (mLod == eLevelofDetail.lodMed)
                    kNumPts = 20;
                DeviceVertexFormat[] v = new DeviceVertexFormat[kNumPts];

                float delta = (float)(UWB_Math.UWB_ToRadians((float)360 / (float)(kNumPts - 2)));

                Color flatColor = mColor1;

                v[0].Position = new Vector3(center.X, center.Y, 0f);
                v[0].Color = flatColor;
                v[0].U = 0.5f;
                v[0].V = 0.5f;

                bool Odd = false;
                for (int i = 0; i < (kNumPts - 2); i++)
                {
                    if (Odd == false)
                    {
                        float X = center.X + (radius * (float)Math.Cos(i * delta));
                        float Y = center.Y + (radius * (float)Math.Sin(i * delta));
                        v[i + 1].Position = new Vector3(X, Y, 0f);
                        v[i + 1].Color = flatColor;
                        v[i + 1].U = 0.5f + (0.5f * (float)Math.Cos(i * delta));
                        v[i + 1].V = 0.5f - (0.5f * (float)Math.Sin(i * delta));
                    }
                    else
                    {
                        float X = center.X + (0.5f * radius * (float)Math.Cos(i * delta));
                        float Y = center.Y + (0.5f * radius * (float)Math.Sin(i * delta));
                        v[i + 1].Position = new Vector3(X, Y, 0f);
                        v[i + 1].Color = flatColor;
                        v[i + 1].U = 0.5f + (0.5f * (float)Math.Cos(i * delta));
                        v[i + 1].V = 0.5f - (0.5f * (float)Math.Sin(i * delta));
                    }
                    Odd = !Odd;
                }
                v[kNumPts - 1] = v[1];

                if (mShadeMode == eShadeMode.smGouraud)
                    v[0].Color = mColor2;

                device.DrawUserPrimitives(PrimitiveType.TriangleFan, v, 0, (kNumPts - 2));
                if (mbTexturingEnabled)
                    UWB_XNAGraphicsSystem.m_TheAPI.DeactivateTexture();

            }
            return true;
        }

        public override bool drawRectangle(Vector3 min, Vector3 max)
        {
            GraphicsDevice device = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            Debug.Assert(device != null, "device not valid on DrawHelper drawRectangle call");
            
            DeviceVertexFormat[] v = new DeviceVertexFormat[6];
            Color flatColor = mColor1;

            v[0].Position = Vector3.Divide((min + max), 2);
            v[0].Color = flatColor;
            v[0].U = 0.5f;
            v[0].V = 0.5f;


            v[1].Position = new Vector3(min.X, max.Y, max.Z);
            v[1].Color = flatColor;
            v[1].U = 1.0f;
            v[1].V = 0.0f;

            v[2].Position = min;
            v[2].Color = flatColor;
            v[2].U = 1.0f;
            v[2].V = 1.0f;

            v[3].Position = new Vector3(max.X, min.Y, max.Z);
            v[3].Color = flatColor;
            v[3].U = 0.0f;
            v[3].V = 1.0f;

            v[4].Position = max;
            v[4].Color = flatColor;
            v[4].U = 0.0f;
            v[4].V = 0.0f;

            v[5] = v[1];

            if (mShadeMode == eShadeMode.smGouraud)
                v[0].Color = mColor2;
            
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, v, 0, 4);
            if (mbTexturingEnabled)
                UWB_XNAGraphicsSystem.m_TheAPI.DeactivateTexture();

            return true;
        }

        public override void setFillMode(eFillMode fillMode)
        {
            GraphicsDevice graphicsDevice = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();

            if (graphicsDevice != null)
            {
                switch (fillMode)
                {
                    case eFillMode.fmSolid:
                        graphicsDevice.RenderState.FillMode = FillMode.Solid;
                        break;
                    case eFillMode.fmPoint:
                        graphicsDevice.RenderState.FillMode = FillMode.Point;
                        break;
                    case eFillMode.fmWireframe:
                        graphicsDevice.RenderState.FillMode = FillMode.WireFrame;
                        break;
                }
            }
        }

        public override bool accumulateModelTransform(
            Vector3 translation,
            Vector3 scale,
            float rotationRadians,
            Vector3 pivot)
        {
            if (UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice() == null)
                return false;

            Vector3 z_axis = new Vector3(0, 0, 1);
            mMatrixStack.TranslateLocal(translation);
            mMatrixStack.TranslateLocal(pivot);
            mMatrixStack.RotateAxisLocal(z_axis, rotationRadians);
            mMatrixStack.ScaleLocal(scale);
            mMatrixStack.TranslateLocal(-pivot);

            UWB_XNAGraphicsSystem.m_TheAPI.setWorldMatrix(mMatrixStack.Top());
            return true;

        }

        public override bool pushModelTransform()
        {
            if (UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice() == null)
                return false;

            mMatrixStack.Push();
            UWB_XNAGraphicsSystem.m_TheAPI.setWorldMatrix(mMatrixStack.Top());
            return true;
        }

        public override bool popModelTransform()
        {
            if (UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice() == null)
                return false;

            mMatrixStack.Pop();
            UWB_XNAGraphicsSystem.m_TheAPI.setWorldMatrix(mMatrixStack.Top());
            return true;
        }

        public override bool initializeModelTransform()
        {
            if (UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice() == null)
                return false;

            mMatrixStack.LoadIdentity();
            UWB_XNAGraphicsSystem.m_TheAPI.setWorldMatrix(mMatrixStack.Top());
            return true;
        }

        public override bool transformPoint(ref Vector3 point)
        {
            Vector3 pt = new Vector3(point.X, point.Y, point.Z);

            Matrix m = mMatrixStack.Top();
            point.X = pt.X * m.M11 + pt.Y * m.M21 + pt.Z * m.M31 + m.M41;
            point.Y = pt.X * m.M12 + pt.Y * m.M22 + pt.Z * m.M32 + m.M42;
            point.Z = pt.X * m.M13 + pt.Y * m.M23 + pt.Z * m.M33 + m.M43;
            return true;
        }

        public override bool enableBlending(bool on)
        {
            GraphicsDevice d = UWB_XNAGraphicsSystem.m_TheAPI.GetActiveDevice();
            if (d != null)
            {
                mbBlendingEnabled = on;

                if (on)
                {
                    d.RenderState.AlphaBlendEnable = true;
                    d.RenderState.SourceBlend = Blend.SourceAlpha;
                    d.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
                    d.RenderState.BlendFunction = BlendFunction.Add;
                    d.RenderState.AlphaTestEnable = true;
                }
                else
                {
                    d.RenderState.AlphaBlendEnable = false;
                }
            }
            return true;
        }

        public override bool enableTexture(bool on)
        {
            mbTexturingEnabled = on;

            if (mbTexturingEnabled)
            {
                if (mTexFileName != "")
                    UWB_XNAGraphicsSystem.m_TheAPI.ActivateTexture(mTexFileName);
            }
            else
            {
                UWB_XNAGraphicsSystem.m_TheAPI.DeactivateTexture();
            }
            return !on;
        }

    }
}
